using System;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Web.Services;

namespace ODX.Core
{
    [WebService(Namespace = "http://codeplex.com/odx")]
    /// <summary>
    /// Wrapper class used to expose <see cref="DbDataProvider"/> as a SingleCall servise.
    /// </summary>
    /// <remarks>
    /// If you do not want to keep any session on server you use SingleCall remoting servises.
    /// Inherit <see cref="SqlDataService"/> and override <see cref="SqlDataService.Provider"/>
    /// property and create DbDataProvider each time it called.
    /// </remarks>
    public class SqlDataService : MarshalByRefObject, ISqlDataProvider
    {
        /// <summary>
        /// Override this property and provide an appropriate data provider.
        /// </summary>
        protected virtual DbDataProvider Provider
        {
            get
            {
                DbDataProvider provider = new DbDataProvider(
                    DbProviderFactories.GetFactory(ConfigurationManager.AppSettings["odx.sql.factory"]),
                    ConfigurationManager.AppSettings["odx.sql.connection"]);

                string nulls = ConfigurationManager.AppSettings["odx.sql.nulls"];
                if ( nulls != null )
                switch ( nulls.ToLower() )
                {
                    case "min" :
                        provider.NullsPosition = NullsPosition.Minimum;
                        break;
                    case "max":
                        provider.NullsPosition = NullsPosition.Maximum;
                        break;
                }

                return provider;
            }
        }
        [WebMethod]
        /// <summary>
        /// Selects records from a data source using specified SQL statement.
        /// </summary>
        /// <param name="selectSql">SQL SELECT statement.</param>
        /// <param name="tableName">Table name to put results into.</param>
        /// <param name="count">Number of records to be retrieved from the data source.</param>
        /// <param name="parameters">Parameters to be used instead '?' marks in sql statement.</param>
        /// <returns>DataSet contained queried data and optionally prefetchd records.</returns>
        public virtual DataSet SelectSql(string selectSql, string tableName, int count, params object[] parameters)
        {
            return Provider.SelectSql(selectSql, tableName, count, parameters);
        }

        [WebMethod]
        /// <summary>
        /// Selects records from a data source using specified filter sort order.
        /// </summary>
        /// <param name="tableName">Table name in data source to be queried.</param>
        /// <param name="filter">Filter expression to be applied to the table. '?' marks are accepted as parameters placeholders</param>
        /// <param name="sort">List of sort fields.</param>
        /// <param name="count">Nubler of records to be queried.</param>
        /// <param name="parameters">Parameters to be used instead '?' in filter expression.</param>
        /// <returns>DataSet contained queried data and optionally prefetched records.</returns>
        public virtual DataSet Select(string tableName, string filter, string sort, int count, params object[] parameters)
        {
            return Provider.Select(tableName, filter, sort, count, parameters);
        }

        [WebMethod]
        /// <summary>
        /// Queries single record from a data source.
        /// </summary>
        /// <param name="tableName">Table name in data source to be queried.</param>
        /// <param name="ID">ID of a record to be returned.</param>
        /// <returns>DataSet contained the requested record and optionally prefetched records.</returns>
        public virtual DataSet GetRecord(string tableName, string ID)
        {
            return Provider.GetRecord(tableName, ID);
        }

        [WebMethod]
        /// <summary>
        /// Returns complete list of child records for the specified parent record.
        /// </summary>
        /// <param name="childTableName">Name of child table.</param>
        /// <param name="childFK">Name of FK field in child table.</param>
        /// <param name="parentID">ID of parent record.</param>
        /// <returns>DataSet contained child records and optionally prefetched records.</returns>
        public virtual DataSet GetChildren(string childTableName, string childFK, string parentID)
        {
            return Provider.GetChildren(childTableName, childFK, parentID);
        }

        [WebMethod]
        /// <summary>
        /// Returns records linked N:M to the specified parent record.
        /// </summary>
        /// <param name="linkTableName">Link table name.</param>
        /// <param name="childTableName">Name of table to query child records</param>
        /// <param name="parentFK">Name of fielf in link table that is FK to the parent table.</param>
        /// <param name="childFK">Name of fielf in link table that is FK to the child table.</param>
        /// <param name="parentID">ID of parent record.</param>
        /// <returns>DataSet contained child records and optionally prefetched records</returns>
        public virtual DataSet GetAssoc(string linkTableName, string childTableName, string parentFK, string childFK,
                                string parentID)
        {
            return Provider.GetAssoc(linkTableName, childTableName, parentFK, childFK, parentID);
        }

        [WebMethod]
        /// <summary>
        /// Saves DataSet to the underlying data source
        /// </summary>
        /// <param name="changes">DataSet, typically contained changes made by user or algorithms.</param>
        /// <param name="saveMode">Concurrent changes processing rules.</param>
        public virtual void Save(DataSet changes, SaveMode saveMode)
        {
            Provider.Save(changes, saveMode);
        }

        /// <summary>
        /// Defines positions of nulls in ordered data. 
        /// </summary>
        public virtual NullsPosition NullsPosition
        {
            get { return Provider.NullsPosition;  }
        }
    }
}
